package com.xtpt.disaster.service.impl;

import com.alibaba.fastjson.JSON;
import com.xtpt.disaster.bean.JobDetail;
import com.xtpt.disaster.bean.NodeInfo;
import com.xtpt.disaster.bean.TaskInfo;
import com.xtpt.disaster.common.File.ClientAgentUrlGenerator;
import com.xtpt.disaster.common.File.FileCmdBuilder;
import com.xtpt.disaster.common.PortalResult;
import com.xtpt.disaster.common.SQLServer.CallbackUrlGenerator;
import com.xtpt.disaster.common.consts.BackupTypeEnum;
import com.xtpt.disaster.common.consts.StatusConst;
import com.xtpt.disaster.service.FileBackupService;
import com.xtpt.disaster.service.JobDetailService;
import com.xtpt.disaster.service.NodeInfoManageService;
import com.xtpt.disaster.service.TaskInfoManageService;
import com.xtpt.disaster.utils.IDGenerator;
import com.xtpt.disaster.utils.ServerPathUtil;
import com.xtpt.disaster.utils.ShellExec;
import com.xtpt.disaster.utils.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;

@Service
public class FileBackupServiceImpl implements FileBackupService {
    @Autowired
    ServerPathUtil serverPathUtil;

    @Autowired
    TaskInfo taskInfo;

    @Autowired
    FileCmdBuilder fileCmdBuilder;

    @Autowired
    NodeInfoManageService nodeInfoManageService;

    @Autowired
    TaskInfoManageService taskInfoManageService;

    @Autowired
    JobDetail jobDetail;

    @Autowired
    ClientAgentUrlGenerator agentUrlGenerator;

    @Autowired
    JobDetailService jobDetailService;

    @Autowired
    CallbackUrlGenerator generator;

    /**
     * @Author jack xin
     * @Method Name FileBackup
     * @Desc 使用openssh实现文件备份服务
     * @Param [client, taskType, clientPath, serverPath]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 9:19 2021/12/28
    **/
    @Override
    public PortalResult FileBackup(NodeInfo client, Integer taskType, String clientPath, String serverPath) {

        String command =  "scp " + " -r " + client.getNodeUsername() + "@" + client.getNodeIp() + ":" + clientPath + "  " + serverPath;
        boolean res = ShellExec.callShell(command);
        if (res) return PortalResult.ok(command);
        else{
            PortalResult result = PortalResult.error("任务执行失败！");
            result.setData(command);
            return result;
        }
    }

    /**
     * @Author jack xin
     * @Method Name FileBackupByAgent
     * @Desc 使用代理实现文件备份服务
     * @Param [taskInfo, backupFileName]
     * @return com.xtpt.disaster.common.PortalResult
     * @Date 9:18 2021/12/28
    **/
    @Override
    public PortalResult FileBackupByAgent(TaskInfo taskInfo, String backupFileName) {
        try{
            Long nodeId = taskInfo.getNodeId();
            NodeInfo nodeInfo = nodeInfoManageService.selectById(nodeId);

            jobDetail.setNodeId(nodeId);

            Long jobId = IDGenerator.longid();
            jobDetail.setJobId(jobId);

            Long taskId = taskInfo.getTaskId();
            jobDetail.setTaskId(taskId);

            Integer dataType = taskInfo.getTaskFileType();

            fileCmdBuilder.initializeWithClientNode(nodeInfo);
            //
            String callbackUrl = generator.urlGenerator("/rest/task/receiver/" + jobId.toString());
            fileCmdBuilder.setResultCallBackUrl(callbackUrl);
            Map<String, String> pathMap=null;
            // 增量备份的处理（通过备份路径和节点id查不到最近一次成功的全量备份则开启一次新的全量备份）
            if(BackupTypeEnum.getObject(taskInfo.getTaskBackupType()) == BackupTypeEnum.INCREMENT)
            {
                String inputClientPath = taskInfo.getTaskClientPath();
                //只有文件夹才支持增量（文件夹需要以路径分隔符结尾）
                if(inputClientPath.endsWith("\\") || inputClientPath.endsWith("/"))
                {
                    // 因为存在数据库的时候就是去除尾部的路径分隔符的
                    String clientFilePath = ServerPathUtil.TrimPathEndSeparator(inputClientPath);
                    // 增量备份的时候找到最近一次的全量
                    JobDetail fullJob= jobDetailService.getByClientPath(nodeId,clientFilePath);
                    if(fullJob!=null)
                    {
                        pathMap = fileCmdBuilder.fileIncrementBackUp(inputClientPath,fullJob.getServerPath(), fullJob.getClientPath());
                    }
                }
            }
            if(pathMap==null) {
                pathMap = fileCmdBuilder.fileBackUp(taskInfo, dataType, backupFileName);
            }
            // 将备份命令转化为json字符串
            String cmd = fileCmdBuilder.buildToJSONString();
            System.out.println("准备提交任务到客户端！");

            // 保存job发出的cmd记录
            System.out.println(cmd);
            System.out.println(cmd.length());

            //写入作业记录到数据库中
            StringBuilder serverFilesPath= new StringBuilder();
            StringBuilder clientFilesPath= new StringBuilder();
            for (Map.Entry<String,String> entry:pathMap.entrySet()){
                serverFilesPath.append(entry.getKey()).append(",");
                clientFilesPath.append(entry.getValue()).append(",");
            }
            Date jobStartTime = TimeUtil.dateMaker();

            Integer jobType = taskInfo.getTaskType();

            Integer jobBackupType = taskInfo.getTaskBackupType();

            Integer scheduleType = taskInfo.getTaskExectype();

            String jobName = taskInfo.getTaskName();

            Long dbId = taskInfo.getDbId();
            // 保存服务端路径
            jobDetail.setServerPath(serverFilesPath.deleteCharAt(serverFilesPath.length()-1).toString());
            // 保存客户端路径
            jobDetail.setClientPath(clientFilesPath.deleteCharAt(clientFilesPath.length()-1).toString());
            //
            jobDetail.setDataType(dataType);
            //
            jobDetail.setJobType(jobType);
            //
            jobDetail.setJobBackupType(jobBackupType);
            //
            jobDetail.setScheduleType(scheduleType);
            //
            jobDetail.setJobName(jobName);

            jobDetail.setDbId(dbId);

            jobDetail.setJobStartTime(jobStartTime);
            // 将job记录存入表中
            jobDetail.setJobCommand(cmd);
            jobDetail.setDataType(taskInfo.getTaskFileType());
            PortalResult res = jobDetailService.insert(jobDetail);
            if(!res.isOK()) {
                return PortalResult.error("备份记录提交到作业表中失败，请检查作业参数!");
            }
            // 将命令提交到代理端执行
            String agentUrl = agentUrlGenerator.generateUrl(nodeInfo);
            String postToClient = cn.hutool.http.HttpUtil.post(agentUrl, cmd);
            System.out.println("提交到客户端成功！");

            jobDetail.setJobResult(postToClient);
            jobDetailService.update(jobDetail);
            PortalResult portalResult = JSON.parseObject(postToClient,PortalResult.class);
            if(!portalResult.getStatus().equals(StatusConst.SUCCESS))
            {
                return PortalResult.error("请求代理客户端失败！");
            }

        } catch (Exception e) {
            e.printStackTrace();
            jobDetail.setJobResult(e.getMessage());
            jobDetail.setJobStatus(StatusConst.ERROR);
            jobDetailService.update(jobDetail);
            return PortalResult.error(e.getMessage());
        }
        return PortalResult.ok("文件备份任务发起成功！");
    }
}
